package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/urfave/cli/v2"
	"github.com/xuri/excelize/v2"
)

type Config struct {
	SourcePath string
	DestPath   string
	Help       string
}

func main() {
	cfg, err := parseFlags()
	if err != nil {
		prompt()
		log.Fatal(err)
	}

	if err := txt2xlsx(cfg); err != nil {
		log.Fatal(err)
	}
}

func txt2xlsx(cfg *Config) error {
	// 打开文本文件
	txtFile, err := os.Open(cfg.SourcePath)
	if err != nil {
		return fmt.Errorf("无法打开输入文件: %v", err)
	}
	defer txtFile.Close()

	// 创建Excel文件
	f := excelize.NewFile()
	defer f.Close()

	// 创建流式写入器（内存优化）
	streamWriter, err := f.NewStreamWriter("Sheet1")
	if err != nil {
		return fmt.Errorf("创建流写入器失败: %v", err)
	}

	// 设置文本格式样式（防止Excel自动转换）
	textStyleID, _ := f.NewStyle(&excelize.Style{
		NumFmt: 49, // 49=文本格式
	})

	scanner := bufio.NewScanner(txtFile)
	scanner.Buffer(make([]byte, 1024*1024), 12*1024*1024)
	rowNum := 1 // Excel行号从1开始
	for scanner.Scan() {
		line := scanner.Text()
		if strings.TrimSpace(line) == "" {
			continue
		}

		if len(line) > 10*1024*1024 { // 超过10MB警告
			log.Printf("警告：第%d行数据过大 (%d MB)", rowNum, len(line)/(1024*1024))
			continue
		}

		// 分割制表符
		fields := strings.Split(line, "\t")
		row := make([]interface{}, len(fields))

		// 处理每个字段
		for i, field := range fields {
			field = strings.TrimSpace(field)

			if len(field) > 32767 {
				field = field[:32767]
				log.Printf("第%d行第%d列被截断", rowNum, i+1)
			}

			if field == "" {
				row[i] = nil // 空单元格
			} else {
				// 关键点：所有内容存储为文本类型
				row[i] = excelize.Cell{
					StyleID: textStyleID,
					Value:   field,
				}
			}
			fields[i] = "" // 帮助GC
		}

		// 流式写入行数据
		cell, _ := excelize.CoordinatesToCellName(1, rowNum)
		if err := streamWriter.SetRow(cell, row); err != nil {
			return fmt.Errorf("写入第%d行失败: %v", rowNum, err)
		}
		rowNum++
	}

	if err := scanner.Err(); err != nil {
		return fmt.Errorf("文件读取错误: %v", err)
	}
	// 结束流式写入
	if err := streamWriter.Flush(); err != nil {
		return fmt.Errorf("刷新数据失败: %v", err)
	}

	// 保存Excel文件
	if err := f.SaveAs(cfg.DestPath); err != nil {
		return fmt.Errorf("保存文件失败: %v", err)
	}

	return nil
}

func parseFlags() (*Config, error) {
	var cfg Config

	app := &cli.App{
		Name:  "txt2xlsx",
		Usage: "txt 转换 xlsx",
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:        "source-file",
				Aliases:     []string{"s"},
				Usage:       "源文件路径",
				Required:    true,
				Destination: &cfg.SourcePath,
			},
			&cli.StringFlag{
				Name:        "dest-file",
				Aliases:     []string{"d"},
				Usage:       "目标文件路径",
				Required:    true,
				Destination: &cfg.DestPath,
			},
		},
		// 移除了冗余的验证
		Action: func(c *cli.Context) error {
			return nil
		},
		CustomAppHelpTemplate: `用法:
   txt2xlsx --source-file /your_path/test.txt --dest-file /your_path/test.xlsx

全局选项:
   {{range .VisibleFlags}}{{.}}
   {{end}}`,
	}

	if err := app.Run(os.Args); err != nil {
		// 返回错误而不是打印，让调用者决定如何处理
		return nil, err
	}

	return &cfg, nil
}

func prompt() string {
	text := `
用法:
   txt2csv --source-file /your_path/test.txt --dest-file /your_path/test.csv
	`
	return text
}
